package com.atguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.order.service.OrderService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper,OrderInfo> implements OrderService {
    @Value("${ware.url}")
    private String wareUrl;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitService rabbitService;



    //提交订单，保存订单信息
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long saveOrderInfo(OrderInfo orderInfo) {
        orderInfo.sumTotalAmount();
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());//订单状态
        String outTradeNo = "ATGUIGU"+System.currentTimeMillis()+new Random().nextInt(1000);
        orderInfo.setOutTradeNo(outTradeNo);//订单交易编号，用于第三方交易使用
        //订单明细商品集合
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        StringBuilder tradeBody = new StringBuilder();
        for (OrderDetail orderDetail : orderDetailList) {
            if (orderDetail.getSkuName().length()>100){
                tradeBody.append(orderDetail.getSkuName().substring(0,100));
            }else {
                tradeBody.append(orderDetail.getSkuName());
            }
        }
        orderInfo.setTradeBody(tradeBody.toString());//订单描述，用于第三方交易
        orderInfo.setCreateTime(new Date());
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE,1);
        orderInfo.setExpireTime(calendar.getTime());
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());//支付状态
        //存储订单信息到数据库
        orderInfoMapper.insert(orderInfo);


        for (OrderDetail orderDetail : orderDetailList) {
            orderDetail.setOrderId(orderInfo.getId());
            //存储订单明细到 order_detail表，对应每件商品
            orderDetailMapper.insert(orderDetail);
        }
        //返回订单号，即id
        return orderInfo.getId();
    }

    //获取订单流水号，用于防止无刷新回退提交订单，切一份存入缓存
    @Override
    public String getTradeNo(String userId) {
        String tradeNo = UUID.randomUUID().toString();
        String tradeKey = "user:"+userId+":tradeCode";
        redisTemplate.opsForValue().set(tradeKey,tradeNo);
        return tradeNo;
    }

    //核对（和缓存）流水号，正确则删除缓存
    @Override
    public boolean checkTradeNo(String tradeNo, String userId) {
        String tradeKey = "user:"+userId+":tradeCode";
        String cacheTradeNo= (String) redisTemplate.opsForValue().get(tradeKey);
        return tradeNo.equals(cacheTradeNo);
    }

    //根据键删除流水号缓存
    @Override
    public void deleteTradeNo(String userId) {
        String tradeKey = "user:"+userId+":tradeCode";
        redisTemplate.delete(tradeKey);
    }

    // 验证库存
    @Override
    public boolean checkStock(Long skuId, Integer skuNum) {
        String result = HttpClientUtil.doGet(wareUrl + "/hasStock?skuId=" + skuId + "&num=" + skuNum);
        return "1".equals(result);
    }

    //订单过期，订单关闭
    @Override
    public void execExpiredOrder(Long orderId) {
        updateOrderStatus(orderId,ProcessStatus.CLOSED);
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);
    }

    //根据订单id，修改订单状态，有状态参数
    @Override
    public void updateOrderStatus(Long orderId, ProcessStatus processStatus) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderId);
        orderInfo.setProcessStatus(processStatus.name());
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        orderInfoMapper.updateById(orderInfo);
    }

    //根据订单id 获取订单信息
    @Override
    public OrderInfo getOrderInfoById(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if (orderInfo != null){
            QueryWrapper<OrderDetail> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("order_id", orderId);
            List<OrderDetail> orderDetailList = orderDetailMapper.selectList(queryWrapper);
            orderInfo.setOrderDetailList(orderDetailList);
        }
        return orderInfo;
    }

    //封装减库存的方法
    @Override
    public void sendOrderStatus(Long orderId) {
        //更新订单状态为 已通知仓库状态
        this.updateOrderStatus(orderId,ProcessStatus.NOTIFIED_WARE);
        //封装减库存的参数，转为json串
        String wareJson = initWareOrder(orderId);
        //利用rabbitMQ发送消息，让库存系统减库存
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_WARE_STOCK,MqConst.ROUTING_WARE_STOCK,wareJson);
    }

    //封装减库存的参数，转为json串
    private String initWareOrder(Long orderId) {
        OrderInfo orderInfo = this.getOrderInfoById(orderId);
        //调用封装的方法，利用orderInfo订单信息，封装为减库存的参数，Map
        Map map = this.initWareOrder(orderInfo);

        return JSON.toJSONString(map);
    }

    //根据orderInfo订单信息，封装为减库存的参数，Map
    @Override
    public Map initWareOrder(OrderInfo orderInfo) {
        HashMap<String,Object> map = new HashMap<>();
        map.put("orderId",orderInfo.getId());
        map.put("consignee", orderInfo.getConsignee());
        map.put("consigneeTel", orderInfo.getConsigneeTel());
        map.put("orderComment", orderInfo.getOrderComment());
        map.put("orderBody", orderInfo.getTradeBody());
        map.put("deliveryAddress", orderInfo.getDeliveryAddress());
        map.put("paymentWay", "2");
        map.put("wareId", orderInfo.getWareId());// 仓库Id ，减库存拆单时需要使用！

        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        List<Map> orderDetails = new ArrayList<>();
        for (OrderDetail orderDetail : orderDetailList) {
            HashMap<String, Object> orderDetailMap = new HashMap<>();
            orderDetailMap.put("skuId", orderDetail.getSkuId());
            orderDetailMap.put("skuNum", orderDetail.getSkuNum());
            orderDetailMap.put("skuName", orderDetail.getSkuName());
            orderDetails.add(orderDetailMap);
        }
        map.put("details", orderDetails);

        return map;
    }


    //拆单，根据原总订单id，和wareSkuMap中指明的分仓库id 对应的skuIds
    // 【Map{"wareId":仓库id,"skuIds":对应该仓库的商品skuid的集合},】 进行拆单，生成对应不同仓库的子订单，返回
    @Override
    public List<OrderInfo> orderSplit(String orderId, String wareSkuMap) {
        OrderInfo orderInfoOrigin = this.getOrderInfoById(Long.parseLong(orderId));
        List<Map> mapList = JSON.parseArray(wareSkuMap, Map.class);
        //声明一个list装拆完单之后的OrderInfo
        List<OrderInfo> subOrderInfoList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(mapList)){
            for (Map map : mapList) {
                //该map中对应的 仓库id
                String wareId = (String)map.get("wareId");
                List<String> skuIds = (List<String>)map.get("skuIds");
                //创建子订单
                OrderInfo subOrderInfo = new OrderInfo();
                BeanUtils.copyProperties(orderInfoOrigin,subOrderInfo);
                subOrderInfo.setParentOrderId(Long.parseLong(orderId));
                subOrderInfo.setId(null);
                subOrderInfo.setWareId(wareId);
                List<OrderDetail> orderDetailList = orderInfoOrigin.getOrderDetailList();
                List<OrderDetail> orderDetails = new ArrayList<>();
                for (OrderDetail orderDetail : orderDetailList) {
                    for (String skuId : skuIds) {
                        if (orderDetail.getSkuId() == Long.parseLong(skuId)){
                            orderDetails.add(orderDetail);
                        }
                    }
                }
                subOrderInfo.setOrderDetailList(orderDetails);
                subOrderInfo.sumTotalAmount();
                //保存拆完的子订单
                this.saveOrderInfo(subOrderInfo);
                //装入list
                subOrderInfoList.add(subOrderInfo);
            }
        }
        this.updateOrderStatus(Long.parseLong(orderId),ProcessStatus.SPLIT);
        return subOrderInfoList;
    }

    //处理过期订单，而且判断 是否还去发消息关闭支付状态
    @Override
    public void execExpiredOrder(Long orderId, String flag) {
        this.updateOrderStatus(orderId,ProcessStatus.CLOSED);
        if ("2".equals(flag)){
            rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);
        }
    }
}
